#ifndef __TCPSOCKETEVENT_H__
#define __TCPSOCKETEVENT_H__

#ifdef __Win32__
#include <winsock2.h>
#include <event2/event-config.h>
#include <ws2tcpip.h>
#include <process.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#endif

#include <assert.h>
#include <time.h>

// use libevent

#include "event.h"
#include "event2/event.h"
#include "event2/buffer.h"
#include "event2/bufferevent.h"
#include "event2/listener.h"
#include "event2/util.h"
#include "event2/thread.h"

//#include "map.h"
#include <map>
//#include "OSMutex.h"
#define MAX_ACCEPT_NUM			(5)

class TcpSocketServer;
class ConnNode;
class ConnQueue;
struct LibeventThread;

class ConnNode
{
	//此类只能由TcpBaseServer创建，
	//并由ConnQueue类管理
	friend class ConnQueue;
	friend class TcpSocketServer;
public:
	ConnNode(evutil_socket_t fd = 0);
	~ConnNode();
	LibeventThread *GetThread() { return m_Thread; }
	evutil_socket_t GetFd() { return m_fd; }
	//获取可读数据的长度
	int GetReadBufferLen()
	{
		return evbuffer_get_length(m_ReadBuf);
	}
	//从读缓冲区中取出len个字节的数据，存入buffer中，若不够，则读出所有数据
	//返回读出数据的字节数
	int GetReadBuffer(char *buffer, int len)
	{
		return evbuffer_remove(m_ReadBuf, buffer, len);
	}
	//从读缓冲区中复制出len个字节的数据，存入buffer中，若不够，则复制出所有数据
	//返回复制出数据的字节数
	//执行该操作后，数据还会留在缓冲区中，buffer中的数据只是原数据的副本
	int CopyReadBuffer(char *buffer, int len)
	{
		return evbuffer_copyout(m_ReadBuf, buffer, len);
	}
	//获取可写数据的长度
	int GetWriteBufferLen()
	{
		return evbuffer_get_length(m_WriteBuf);
	}
	//将数据加入写缓冲区，准备发送
	int AddToWriteBuffer(char *buffer, int len)
	{
		printf("m_WriteBuf's len =%d\n",evbuffer_get_length(m_WriteBuf));
		//if(evbuffer_get_length(m_WriteBuf) < 32768)
			//return -1;
		//if(evbuffer_get_length(m_WriteBuf)<10000000000)
		//OSMutexLocker locker(&m_mutex);
		return evbuffer_add(m_WriteBuf, buffer, len);
	}
    /*
     *  Usage:
     *  1.派生类添加静态函数,在函数中free掉申请的数据
     *    static void xxx(const void* pData,size_t len,void* arg);
     *    {
     *       if(pData)
     *          free(pData);
     *    }
     *  2.调用AddToWriteBufferRef
     *    char* buffer = malloc(sizeof(1024*1024));
     *    conn->AddToWriteBufferRef(buffer,1024*1024,xxx,NULL);
     *
     *  这样buffer中数据不会拷贝到WriteBuffer中，当buffer中的数据全部移到输出缓冲区后，
     *  xxx函数会被回调，buffer也会被销毁。
     */
    int AddToWriteBufferRef(char *buffer,int len,
                            void (*free_resource)(const void* pData,size_t len,void* arg),
                            void* arg)
    {
        //if(free_resource == NULL)
        //{
          //  printf("free_resource func is NULL\n");
        //}
       return evbuffer_add_reference(m_WriteBuf,buffer,len,free_resource,arg);
    }

    int AddFileToWriteBuffer(evutil_socket_t fd,ev_off_t offset,size_t length)
    {
        return evbuffer_add_file(m_WriteBuf,fd,offset,length);
    }
	//将读缓冲区中的数据移动到写缓冲区
	void MoveBufferData()
	{
		evbuffer_add_buffer(m_WriteBuf, m_ReadBuf);
	}
    /**
     *  将输入缓冲区中的所有数据移动到输出缓冲区（尽可能不发生拷贝）
     *  @return 成功返回0，失败返回-1
     */
    int MoveBufferDataByRef()
    {
        return evbuffer_add_buffer_reference(m_WriteBuf,m_ReadBuf);
    }
    /**
     *  从输入缓冲区取出一行数据，不包含行结束符。行结束符可以时\r\n或者
     *  \n，如果没有整行供读取，函数返回空。
     *  @param size_t* nReadout 返回的字符串的字节数
     *  @return 返回字符串的首地址
     *  @note 返回的字符串需要自己调用free释放
     */
    char* ReadLineFromReadBuffer(size_t* nReadout)
    {
        return evbuffer_readln(m_ReadBuf,nReadout,EVBUFFER_EOL_CRLF);
    }
    int DeleteFromReadBuffer(int len)
    {
        return evbuffer_drain(m_ReadBuf,len);
    }
private:
	LibeventThread *m_Thread;
	const evutil_socket_t m_fd;
	ConnNode *m_Prev;				//前一个结点的指针
	ConnNode *m_Next;				//后一个结点的指针
	evbuffer *m_ReadBuf;
	evbuffer *m_WriteBuf;
	//OSMutex m_mutex;
};

//带头尾结点的双链表类，每个结点存储一个连接的数据
class ConnQueue
{
public:
	ConnQueue();
	~ConnQueue();
	ConnNode *InsertConnNode(evutil_socket_t fd, LibeventThread *t);
	void DeleteConnNode(ConnNode *c);
	void PrintQueue();
private:
	ConnNode *m_head;
	ConnNode *m_tail;
	int m_NodeCount;
};

struct LibeventThread
{
#ifdef WIN32
	HANDLE          tid;		//线程的ID
#else
	pthread_t       tid;	//线程的ID
#endif
	struct event_base *base;			//libevent的事件处理机
	struct event notifyEvent;			//监听管理的事件机
	evutil_socket_t notifyReceiveFd;	//管理的接收端
	evutil_socket_t notifySendFd;		//管道的发送端
	ConnQueue connectQueue;				//socket连接的链表
										//在libevent的事件处理中要用到很多回调函数，不能使用类隐含的this指针
										//所以用这样方式将TcpBaseServer的类指针传过去
	TcpSocketServer  *tcpConnect;		//TcpSocketServer 类的指针
};

class TcpSocketServer
{
public:
	static const int EXIT_CODE = -1;
	TcpSocketServer(int threadCount = 0);
	~TcpSocketServer();
	//设置监听的端口号，如果不需要监听，请将其设置为EXIT_CODE
	void SetPort(int port)
	{
		m_Port = port;
	}
	//开始事件循环
	bool StartRun();
	//在tv时间里结束事件循环
	//是否tv为空，则立即停止
	void StopRun(timeval *tv);

	//添加和删除信号处理事件
	//sig是信号，ptr为要回调的函数
	bool AddSignalEvent(int sig, void(*ptr)(int, short, void*));
	bool DeleteSignalEvent(int sig);

	//添加和删除定时事件
	//ptr为要回调的函数，tv是间隔时间，once决定是否只执行一次
	event *AddTimerEvent(void(*ptr)(int, short, void*),
		timeval tv, bool once);
	bool DeleteTimerEvent(event *ev);
private:
	//初始化子线程的数据
	void SetupThread(LibeventThread *thread);

	//子线程的入口函数
#ifdef __Win32__
	static unsigned int WINAPI WorkerLibevent(LPVOID inThread);
#else
	static void *WorkerLibevent(void *arg);
#endif
	//（主线程收到请求后），对应子线程的处理函数
	static void ThreadProcess(int fd, short which, void *arg);
	//static void ThreadProcess(struct bufferevent* bev,void *arg);
	//被libevent回调的各个静态函数
	static void ListenerEventCb(evconnlistener *listener, evutil_socket_t fd,
		sockaddr *sa, int socklen, void *user_data);
	static void ReadEventCb(struct bufferevent *bev, void *data);
	static void WriteEventCb(struct bufferevent *bev, void *data);
	static void CloseEventCb(struct bufferevent *bev, short events, void *data);
protected:
	//这五个虚函数，一般是要被子类继承，并在其中处理具体业务的

	//新建连接成功后，会调用该函数
	virtual void ConnectionEvent(ConnNode *conn) { }

	//读取完数据后，会调用该函数
	virtual void ReadEvent(ConnNode *conn) { }

	//发送完成功后，会调用该函数（因为串包的问题，所以并不是每次发送完数据都会被调用）
	virtual void WriteEvent(ConnNode *conn) { }

	//断开连接（客户自动断开或异常断开）后，会调用该函数
	virtual void CloseEvent(ConnNode *conn, short events) { }

	//发生致命错误（如果创建子线程失败等）后，会调用该函数
	//该函数的默认操作是输出错误提示，终止程序
	virtual void ErrorQuit(const char *str);

private:
	int m_ThreadCount;					//子线程数
	int m_Port;							//监听的端口
	LibeventThread *m_MainBase;			//主线程的libevent事件处理机
	LibeventThread *m_Threads;			//存储各个子线程信息的数组
	std::map<int, event> m_SignalEvents;	//自定义的信号处理
};

#endif
